home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 2 / LSD and 17bit Compendium Deluxe - Volume II.iso / a / prog / cprog / metre.lha / gram.y < prev    next >
Encoding:
Text File  |  1994-09-07  |  36.0 KB  |  1,432 lines

  1. /*************************************************************
  2.    Copyright (c) 1993,1994 by Paul Long  All rights reserved.
  3. **************************************************************/
  4.  
  5. /*************************************************************
  6.    gram.y - This source file contains the YACC grammar and
  7.             actions for Metre's Standard C parser.  It also
  8.             contains main(), error-handling functions,
  9.             trigger-firing functions, functions that
  10.             maintain the typedef symbol table, functions
  11.             that administer the execution of Metre,
  12.             functions that can be called from the rules()
  13.             function, and a replacement for YACC's
  14.             yyerror().  As you can see, most of the grammar
  15.             rules have no actions.  This is because the
  16.             grammar is largely used to just skip over the
  17.             parts of C that Metre doesn't care about.
  18. **************************************************************/
  19.  
  20.  
  21. %token TK_IDENTIFIER TK_CONSTANT TK_STRING_LITERAL TK_SIZEOF
  22. %token TK_PTR_OP TK_INC_OP TK_DEC_OP TK_LEFT_OP TK_RIGHT_OP
  23. %token TK_LE_OP TK_GE_OP TK_EQ_OP TK_NE_OP
  24. %token TK_AND_OP TK_OR_OP TK_MUL_ASSIGN TK_DIV_ASSIGN TK_MOD_ASSIGN
  25. %token TK_ADD_ASSIGN TK_SUB_ASSIGN TK_LEFT_ASSIGN TK_RIGHT_ASSIGN TK_AND_ASSIGN
  26. %token TK_XOR_ASSIGN TK_OR_ASSIGN TK_TYPE_NAME
  27.  
  28. %token TK_TYPEDEF TK_EXTERN TK_STATIC TK_AUTO TK_REGISTER
  29. %token TK_CHAR TK_SHORT TK_INT TK_LONG TK_SIGNED TK_UNSIGNED
  30. %token TK_FLOAT TK_DOUBLE TK_CONST TK_VOLATILE TK_VOID
  31. %token TK_STRUCT TK_UNION TK_ENUM TK_ELIPSIS TK_RANGE
  32.  
  33. %token TK_CASE TK_DEFAULT TK_IF TK_ELSE TK_SWITCH TK_WHILE TK_DO TK_FOR
  34. %token TK_GOTO TK_CONTINUE TK_BREAK TK_RETURN
  35.  
  36. %start translation_unit
  37.  
  38. /* Used to disambiguate if from if/else. */
  39. %nonassoc THEN
  40. %nonassoc TK_ELSE
  41.  
  42. %%
  43.  
  44. primary_expr
  45.    : identifier
  46.    | TK_CONSTANT
  47.    | string_list
  48.    | '(' expr ')'
  49.    ;
  50.  
  51. string_list
  52.    : TK_STRING_LITERAL
  53.    | string_list TK_STRING_LITERAL
  54.    ;
  55.  
  56. postfix_expr
  57.    : primary_expr
  58.    | postfix_expr '[' expr ']'
  59.    | postfix_expr '(' ')'
  60.    | postfix_expr '(' argument_expr_list ')'
  61.    | postfix_expr '.' identifier
  62.    | postfix_expr TK_PTR_OP identifier
  63.    | postfix_expr TK_INC_OP
  64.    | postfix_expr TK_DEC_OP
  65.    ;
  66.  
  67. argument_expr_list
  68.    : assignment_expr
  69.    | argument_expr_list ',' assignment_expr
  70.    ;
  71.  
  72. unary_expr
  73.    : postfix_expr
  74.    | TK_INC_OP unary_expr
  75.    | TK_DEC_OP unary_expr
  76.    | unary_operator cast_expr
  77.    | TK_SIZEOF unary_expr
  78.    | TK_SIZEOF '(' type_name ')'
  79.    ;
  80.  
  81. unary_operator
  82.    : '&'
  83.    | '*'
  84.    | '+'
  85.    | '-'
  86.    | '~'
  87.    | '!'
  88.    ;
  89.  
  90. cast_expr
  91.    : unary_expr
  92.    | '(' type_name ')' cast_expr
  93.    ;
  94.  
  95. multiplicative_expr
  96.    : cast_expr
  97.    | multiplicative_expr '*' cast_expr
  98.    | multiplicative_expr '/' cast_expr
  99.    | multiplicative_expr '%' cast_expr
  100.    ;
  101.  
  102. additive_expr
  103.    : multiplicative_expr
  104.    | additive_expr '+' multiplicative_expr
  105.    | additive_expr '-' multiplicative_expr
  106.    ;
  107.  
  108. shift_expr
  109.    : additive_expr
  110.    | shift_expr TK_LEFT_OP additive_expr
  111.    | shift_expr TK_RIGHT_OP additive_expr
  112.    ;
  113.  
  114. relational_expr
  115.    : shift_expr
  116.    | relational_expr '<' shift_expr
  117.    | relational_expr '>' shift_expr
  118.    | relational_expr TK_LE_OP shift_expr
  119.    | relational_expr TK_GE_OP shift_expr
  120.    ;
  121.  
  122. equality_expr
  123.    : relational_expr
  124.    | equality_expr TK_EQ_OP relational_expr
  125.    | equality_expr TK_NE_OP relational_expr
  126.    ;
  127.  
  128. and_expr
  129.    : equality_expr
  130.    | and_expr '&' equality_expr
  131.    ;
  132.  
  133. exclusive_or_expr
  134.    : and_expr
  135.    | exclusive_or_expr '^' and_expr
  136.    ;
  137.  
  138. inclusive_or_expr
  139.    : exclusive_or_expr
  140.    | inclusive_or_expr '|' exclusive_or_expr
  141.    ;
  142.  
  143. logical_and_expr
  144.    : inclusive_or_expr
  145.    | logical_and_expr TK_AND_OP inclusive_or_expr
  146.    ;
  147.  
  148. logical_or_expr
  149.    : logical_and_expr
  150.    | logical_or_expr TK_OR_OP logical_and_expr
  151.    ;
  152.  
  153. conditional_expr
  154.    : logical_or_expr
  155.    | logical_or_expr '?' expr ':' conditional_expr
  156.       /* I consider the conditional operator to be a decision point. */
  157.       { ++fcn_decisions; }
  158.    ;
  159.  
  160. assignment_expr
  161.    : conditional_expr
  162.    | unary_expr assignment_operator assignment_expr
  163.    ;
  164.  
  165. assignment_operator
  166.    : '='
  167.    | TK_MUL_ASSIGN
  168.    | TK_DIV_ASSIGN
  169.    | TK_MOD_ASSIGN
  170.    | TK_ADD_ASSIGN
  171.    | TK_SUB_ASSIGN
  172.    | TK_LEFT_ASSIGN
  173.    | TK_RIGHT_ASSIGN
  174.    | TK_AND_ASSIGN
  175.    | TK_XOR_ASSIGN
  176.    | TK_OR_ASSIGN
  177.    ;
  178.  
  179. expr
  180.    : assignment_expr
  181.    | expr ',' assignment_expr
  182.    ;
  183.  
  184. constant_expr
  185.    : conditional_expr
  186.    ;
  187.  
  188. declaration
  189.    /*
  190.       Regardless of whether we were really parsing a typedef, indicate that
  191.       we are no longer by setting is_typedef to FALSE.
  192.    */
  193.    : declaration_specifiers ';'
  194.       { is_typedef = FALSE; }
  195.    | declaration_specifiers init_declarator_list ';'
  196.       { is_typedef = FALSE; }
  197.    ;
  198.  
  199. declaration_specifiers
  200.    /*
  201.       nested_decl_specs is incremented and decremented here so that the
  202.       type name of the root-level declaration in a typedef can be
  203.       distinguished from other identifiers in the typedef.
  204.    */
  205.    : storage_class_specifier
  206.    | storage_class_specifier
  207.       { ++nested_decl_specs; }
  208.       declaration_specifiers
  209.       { --nested_decl_specs; }
  210.    | type_specifier
  211.    | type_specifier
  212.       { ++nested_decl_specs; }
  213.       declaration_specifiers
  214.       { --nested_decl_specs; }
  215.    ;
  216.  
  217. init_declarator_list
  218.    : init_declarator
  219.    | init_declarator_list ',' init_declarator
  220.    ;
  221.  
  222. init_declarator
  223.    : declarator
  224.    | declarator '=' initializer
  225.    ;
  226.  
  227. storage_class_specifier
  228.    : TK_TYPEDEF
  229.       /*
  230.          Indicate that we are within a typedef.  This is used to find the
  231.          type name so that it can be added to the typedef symbol table.
  232.       */
  233.       { is_typedef = TRUE; }
  234.    | TK_EXTERN
  235.    | TK_STATIC
  236.    | TK_AUTO
  237.    | TK_REGISTER
  238.    ;
  239.  
  240. type_specifier
  241.    : TK_CHAR
  242.    | TK_SHORT
  243.    | TK_INT
  244.    | TK_LONG
  245.    | TK_SIGNED
  246.    | TK_UNSIGNED
  247.    | TK_FLOAT
  248.    | TK_DOUBLE
  249.    | TK_CONST
  250.    | TK_VOLATILE
  251.    | TK_VOID
  252.    | struct_or_union_specifier
  253.    | enum_specifier
  254.    | TK_TYPE_NAME
  255.    ;
  256.  
  257. struct_or_union_specifier
  258.    /*
  259.       In the following rules, regardless of whether there was a tag, indicate
  260.       that we are no longer looking for one by setting looking_for_tag to FALSE.
  261.    */
  262.    : struct_or_union identifier
  263.       { looking_for_tag = FALSE; }
  264.       '{' struct_declaration_list '}'
  265.    | struct_or_union '{'
  266.       { looking_for_tag = FALSE; }
  267.       struct_declaration_list '}'
  268.    | struct_or_union identifier
  269.       { looking_for_tag = FALSE; }
  270.    ;
  271.  
  272. struct_or_union
  273.    /*
  274.       Indicate that we are looking for a tag.  This information is passed
  275.       to the lexer.  Since tags are in a separate name space from other
  276.       identifiers, this helps the lexer determine whether a lexeme is an
  277.       identifier or a type name.
  278.    */
  279.    : TK_STRUCT
  280.       { looking_for_tag = TRUE; }
  281.    | TK_UNION
  282.       { looking_for_tag = TRUE; }
  283.    ;
  284.  
  285. struct_declaration_list
  286.    : struct_declaration
  287.    | struct_declaration_list struct_declaration
  288.    ;
  289.  
  290. struct_declaration
  291.    : type_specifier_list struct_declarator_list ';'
  292.    ;
  293.  
  294. struct_declarator_list
  295.    : struct_declarator
  296.    | struct_declarator_list ',' struct_declarator
  297.    ;
  298.  
  299. struct_declarator
  300.    : declarator
  301.    | ':' constant_expr
  302.    | declarator ':' constant_expr
  303.    ;
  304.  
  305. enum_specifier
  306.    /*
  307.       In the following rules, regardless of whether there was a tag, indicate
  308.       that we are no longer looking for one by setting looking_for_tag to FALSE.
  309.    */
  310.    : enum '{' enumerator_list '}'
  311.       { looking_for_tag = FALSE; }
  312.    | enum identifier
  313.       { looking_for_tag = FALSE; }
  314.       '{' enumerator_list '}'
  315.    | enum identifier
  316.       { looking_for_tag = FALSE; }
  317.    ;
  318.  
  319. enum
  320.    /*
  321.       Indicate that we are looking for a tag.  See struct_or_union for more
  322.       info.
  323.    */
  324.    : TK_ENUM
  325.       { looking_for_tag = TRUE; }
  326.    ;
  327.  
  328. enumerator_list
  329.    : enumerator
  330.    | enumerator_list ',' enumerator
  331.    ;
  332.  
  333. enumerator
  334.    : identifier
  335.    | identifier '=' constant_expr
  336.    ;
  337.  
  338. declarator
  339.    : declarator2
  340.    | pointer declarator2
  341.    ;
  342.  
  343. declarator2
  344.    : identifier
  345.       {
  346.          /*
  347.             If we are parsing a typedef and this is the root-level declaration,
  348.             this identifier must be the type name that is being being defined
  349.             by the typedef.  Therefore, add it to the typedef symbol table so
  350.             that the lexer can distinguish type names from identifiers.
  351.          */
  352.          if (is_typedef && nested_decl_specs == 0)
  353.            typedef_symbol_table_add(token());
  354.       }
  355.    | '(' declarator ')'
  356.    | declarator2 '[' ']'
  357.    | declarator2 '[' constant_expr ']'
  358.    /*
  359.       For the next three rules, if we are not within a function definition
  360.       already, use the last identifier as the function name.
  361.    */
  362.    | declarator2 '('
  363.       {
  364.          if (!is_within_function)
  365.             strcpy(function_name, last_identifier);
  366.       }
  367.       ')'
  368.    /*
  369.       nested_decl_specs is incremented and decremented in the following two
  370.       rules so that the type name of the root-level declaration in a typedef
  371.       can be distinguished from other identifiers in the typedef.
  372.    */
  373.    | declarator2 '('
  374.       {
  375.          ++nested_decl_specs;
  376.          if (!is_within_function)
  377.             strcpy(function_name, last_identifier);
  378.       }
  379.       parameter_type_list
  380.       { --nested_decl_specs; }
  381.       ')'
  382.    | declarator2 '('
  383.       {
  384.          ++nested_decl_specs;
  385.          if (!is_within_function)
  386.             strcpy(function_name, last_identifier);
  387.       }
  388.       parameter_identifier_list
  389.       { --nested_decl_specs; }
  390.       ')'
  391.    ;
  392.  
  393. pointer
  394.    : '*'
  395.    | '*' type_specifier_list
  396.    | '*' pointer
  397.    | '*' type_specifier_list pointer
  398.    ;
  399.  
  400. type_specifier_list
  401.    : type_specifier
  402.    | type_specifier_list type_specifier
  403.    ;
  404.  
  405. parameter_identifier_list
  406.    : identifier_list
  407.    | identifier_list ',' TK_ELIPSIS
  408.    ;
  409.  
  410. identifier_list
  411.    : identifier
  412.    | identifier_list ',' identifier
  413.    ;
  414.  
  415. parameter_type_list
  416.    : parameter_list
  417.    | parameter_list ',' TK_ELIPSIS
  418.    ;
  419.  
  420. parameter_list
  421.    : parameter_declaration
  422.    | parameter_list ',' parameter_declaration
  423.    ;
  424.  
  425. parameter_declaration
  426.    : type_specifier_list declarator
  427.    | type_name
  428.    ;
  429.  
  430. type_name
  431.    : type_specifier_list
  432.    | type_specifier_list abstract_declarator
  433.    ;
  434.  
  435. abstract_declarator
  436.    : pointer
  437.    | direct_abstract_declarator
  438.    | pointer direct_abstract_declarator
  439.    ;
  440.  
  441. direct_abstract_declarator
  442.    : '(' abstract_declarator ')'
  443.    | '[' ']'
  444.    | '[' constant_expr ']'
  445.    | direct_abstract_declarator '[' ']'
  446.    | direct_abstract_declarator '[' constant_expr ']'
  447.    | '(' ')'
  448.    | '(' parameter_type_list ')'
  449.    | direct_abstract_declarator '(' ')'
  450.    | direct_abstract_declarator '(' parameter_type_list ')'
  451.    ;
  452.  
  453. initializer
  454.    : assignment_expr
  455.    | '{' initializer_list '}'
  456.    | '{' initializer_list ',' '}'
  457.    ;
  458.  
  459. initializer_list
  460.    : initializer
  461.    | initializer_list ',' initializer
  462.    ;
  463.  
  464. statement
  465.    : labeled_statement
  466.    | compound_statement
  467.       {
  468.          is_else = is_if = FALSE;
  469.  
  470.          ++int_fcn.high;      /* High-level statement. */
  471.  
  472.          /* Used to consider adjacent case labels as one decision point. */
  473.          not_case_label();
  474.  
  475.          /*
  476.             Indicate at the end of a compound, high-level statement, then
  477.             fire the end-of-statement trigger.
  478.          */
  479.          int_stm.is_comp = int_stm.is_high = int_stm.end = TRUE;
  480.          int_stm.depth = depth;
  481.          fire_stm();
  482.          ZERO(int_stm);
  483.       }
  484.    | expression_statement
  485.       {
  486.          check_multiple_statements();
  487.  
  488.          ++int_fcn.low;          /* Low-level statement. */
  489.  
  490.          /* Used to consider adjacent case labels as one decision point. */
  491.          not_case_label();
  492.  
  493.          /*
  494.             Indicate at the end of an expression, low-level statement, then
  495.             fire the end-of-statement trigger.
  496.          */
  497.          int_stm.is_expr = int_stm.is_low = int_stm.end = TRUE;
  498.          int_stm.depth = depth;
  499.          fire_stm();
  500.          ZERO(int_stm);
  501.       }
  502.    | selection_statement
  503.       {
  504.          ++int_fcn.high;      /* High-level statement. */
  505.  
  506.          /* Used to consider adjacent case labels as one decision point. */
  507.          not_case_label();
  508.  
  509.          /*
  510.             Indicate at the end of a selection, high-level statement, then
  511.             fire the end-of-statement trigger.
  512.          */
  513.          int_stm.is_select = int_stm.is_high = int_stm.end = TRUE;
  514.          int_stm.depth = depth;
  515.          fire_stm();
  516.          ZERO(int_stm);
  517.       }
  518.    | iteration_statement
  519.       {
  520.          ++int_fcn.high;      /* High-level statement. */
  521.  
  522.          /* Used to consider adjacent case labels as one decision point. */
  523.          not_case_label();
  524.  
  525.          /*
  526.             Indicate at the end of an iteration, high-level statement, then
  527.             fire the end-of-statement trigger.
  528.          */
  529.          int_stm.is_iter = int_stm.is_high = int_stm.end = TRUE;
  530.          int_stm.depth = depth;
  531.          fire_stm();
  532.          ZERO(int_stm);
  533.       }
  534.    | jump_statement
  535.       {
  536.          check_multiple_statements();
  537.  
  538.          ++int_fcn.low;          /* Low-level statement. */
  539.  
  540.          /* Used to consider adjacent case labels as one decision point. */
  541.          not_case_label();
  542.  
  543.          /*
  544.             Indicate at the end of a jump, low-level statement, then
  545.             fire the end-of-statement trigger.
  546.          */
  547.          int_stm.is_jump = int_stm.is_low = int_stm.end = TRUE;
  548.          int_stm.depth = depth;
  549.          fire_stm();
  550.          ZERO(int_stm);
  551.       }
  552.    ;
  553.  
  554. labeled_statement
  555.    : identifier ':' statement
  556.       { is_else = is_if = FALSE; }
  557.    | TK_CASE constant_expr ':'
  558.       {
  559.          check_multiple_statements();
  560.  
  561.          /* Used to consider adjacent case labels as one decision point. */
  562.          case_label();
  563.       }
  564.       statement
  565.    | TK_DEFAULT ':'
  566.       { check_multiple_statements(); }
  567.       statement
  568.    ;
  569.  
  570. compound_statement
  571.    : '{' '}'
  572.    | '{' statement_list '}'
  573.    | '{' declaration_list '}'
  574.    | '{' declaration_list statement_list '}'
  575.    ;
  576.  
  577. declaration_list
  578.    : declaration
  579.    | declaration_list declaration
  580.    ;
  581.  
  582. statement_list
  583.    : statement
  584.    | statement_list statement
  585.    ;
  586.  
  587. expression_statement
  588.    : ';'
  589.    | expr ';'
  590.    ;
  591.  
  592. selection_statement
  593.    : TK_IF '(' expr ')'
  594.       {
  595.          is_if = TRUE;
  596.          check_multiple_statements();
  597.          ++depth;                /* Increase control depth. */
  598.          ++fcn_decisions;        /* This is a decision point. */
  599.       }
  600.       statement
  601.       { --depth;                 /* Decrease control depth. */ }
  602.       opt_else
  603.    | TK_SWITCH '(' expr ')'
  604.       {
  605.          check_multiple_statements();
  606.          ++depth;                /* Increase control depth. */
  607.       }
  608.       statement
  609.       { --depth;                 /* Decrease control depth. */ }
  610.    ;
  611.  
  612. opt_else
  613.    :                              %prec THEN
  614.    | TK_ELSE
  615.       {
  616.          check_multiple_statements();
  617.          is_else = TRUE;         /* Must be after check_...() */
  618.          ++depth;                /* Increase control depth. */
  619.       }
  620.       statement
  621.       { --depth;                 /* Decrease control depth. */ }
  622.    ;
  623.  
  624. iteration_statement
  625.    : TK_WHILE '(' expr ')'
  626.       {
  627.          check_multiple_statements();
  628.          ++depth;                /* Increase control depth. */
  629.          ++fcn_decisions;        /* This is a decision point. */
  630.       }
  631.       statement
  632.       { --depth;                 /* Decrease control depth. */ }
  633.    | TK_DO
  634.       {
  635.          ++depth;                /* Increase control depth. */
  636.          ++fcn_decisions;        /* This is a decision point. */
  637.       }
  638.       statement
  639.       { --depth;                 /* Decrease control depth. */ }
  640.       TK_WHILE '(' expr ')' ';'
  641.       { check_multiple_statements(); }
  642.    | TK_FOR '(' opt_expr ';' ';' opt_expr ')'
  643.       {
  644.          check_multiple_statements();
  645.          ++depth;                /* Increase control depth. */
  646.          /* NOTE: This for statement does not contain a decision point. */
  647.       }
  648.       statement
  649.       { --depth;                 /* Decrease control depth. */ }
  650.    | TK_FOR '(' opt_expr ';' expr ';' opt_expr ')'
  651.       {
  652.          check_multiple_statements();
  653.          ++depth;                /* Increase control depth. */
  654.          ++fcn_decisions;        /* This is a decision point. */
  655.       }
  656.       statement
  657.       { --depth;                 /* Decrease control depth. */ }
  658.    ;
  659.  
  660. opt_expr
  661.    :
  662.    | expr
  663.    ;
  664.  
  665. jump_statement
  666.    : TK_GOTO identifier ';'
  667.    | TK_CONTINUE ';'
  668.    | TK_BREAK ';'
  669.    | TK_RETURN opt_expr ';'
  670.    ;
  671.  
  672. translation_unit
  673.    : external_declaration
  674.    | translation_unit external_declaration
  675.    ;
  676.  
  677. external_declaration
  678.    : function_definition
  679.       { stat_func_end(); }
  680.    | declaration
  681.    ;
  682.  
  683. function_definition
  684.    : declarator
  685.       { stat_func_begin(); }
  686.       function_body
  687.    | declaration_specifiers declarator
  688.       { stat_func_begin(); }
  689.       function_body
  690.    ;
  691.  
  692. function_body
  693.    : compound_statement
  694.    | declaration_list compound_statement
  695.    ;
  696.  
  697. identifier
  698.    : TK_IDENTIFIER
  699.       {
  700.          /*
  701.             Save this identifier in case token buffer (yytext[]) gets
  702.             overwritten by the time the identifier is needed.
  703.          */
  704.          strcpy(last_identifier, token());
  705.       }
  706.    ;
  707. %%
  708. /*************************************************************
  709.    Copyright (c) 1993,1994 by Paul Long  All rights reserved.
  710. **************************************************************/
  711.  
  712. #include <stdio.h>
  713. #include <limits.h>
  714. #include <stdarg.h>
  715. #include "metreint.h"
  716.  
  717. /* External variables. */
  718.  
  719. /*
  720.    Metre maintains statistics in the int_* structures, e.g., int_prj.  The
  721.    structures with the unadorned names, e.g., prj, are used to communicate with
  722.    the rules.  They are zero-filled except when a trigger is being fired.  At
  723.    that time, the contents of the corresponding int_* structure is copied
  724.    to it, the rules() function is called, and then the structure is zero-filed
  725.    again.
  726. */
  727. PRJ prj, int_prj;    /* Project. */
  728. MOD mod, int_mod;    /* Module. */
  729. FCN fcn;             /* Function. */
  730. static FCN int_fcn;
  731. STM stm;             /* Statement. */
  732. static STM int_stm;
  733. LIN lin, int_lin;    /* Line. */
  734. LEX lex, int_lex;    /* Lexeme. */
  735.  
  736. /*
  737.    Which command-line argument (argv) at which to start looking for the next
  738.    file name to process and original file name, respectively.
  739. */
  740. unsigned next_cmd_line_file;
  741. unsigned next_cmd_line_file_orig_n;
  742.  
  743. /* Number of decision points and functions in module (file). */
  744. unsigned mod_decisions;
  745. unsigned mod_functions;
  746.  
  747. /*
  748.    Indicates whether we are looking for a tag.  Parser writes it, lexer reads
  749.    it.  Since tags are in a separate name space from other identifiers, this
  750.    helps the lexer determine whether a lexeme is an identifier or a type name.
  751. */
  752. BOOLEAN looking_for_tag;
  753.  
  754. /*
  755.    Indicates whether we are within a function definition.  Used to determine
  756.    whether to use the last identifier as the function name.
  757. */
  758. BOOLEAN is_within_function;
  759.  
  760. /*
  761.    Name of current input file and name of original file, if specified on
  762.    command line with the substitute-file-name option.  If substitute not
  763.    provided, input_file_orig_name points to the same name as input_file.
  764. */
  765. char *input_file;
  766. char *input_file_orig_name;
  767.  
  768. /* Where all output is written. */
  769. FILE *out_fp;
  770.  
  771. /* Global versions of main's argc and argv. */
  772. int cmd_line_argc;
  773. char **cmd_line_argv;
  774.  
  775. /*
  776.    Block within which typedef type names are held in the typedef symbol-table.
  777. */
  778. typedef struct typedef_sym_blk {
  779.    struct typedef_sym_blk *next;          /* Next block. */
  780.    unsigned total;                        /* Total in this block. */
  781.    char *id[TYPEDEF_SYMBOLS_PER_BLOCK]; /* Array of pointers to type names. */
  782. } TYPEDEF_SYM_BLK;
  783.  
  784. /*
  785.    Head of the typedef symbol-table.  NOTE: This is the only symbol table in
  786.    Metre, and it is used just to hold typedef type names, not all symbols.
  787. */
  788. TYPEDEF_SYM_BLK *typedef_sym_tbl_head = NULL;
  789.  
  790.  
  791. /* Static variables. */
  792.  
  793. /* Control depth--current number of nested control structures. */
  794. static unsigned depth;
  795.  
  796. /* Used to determine how many statements are on a line. */
  797. static unsigned previous_statements_line_number;
  798.  
  799. /* Number of decision points in function. */
  800. static unsigned fcn_decisions;
  801.  
  802. /*
  803.    Metre maintains the number of statements appearing on a line.
  804.    The is_if and is_else BOOLEANs are used principally to relax the
  805.    criteria for what constitutes a statement.  For example, "else if,"
  806.    is not considered two statements because this is a common idiom.
  807. */
  808. static BOOLEAN is_else, is_if;
  809.  
  810. /*
  811.    is_typedef indicates whether we are parsing a typedef.  Since typedefs
  812.    cannot be nested, it's okay that this is just a BOOLEAN.  This is used to
  813.    find the type name of a typedef so that it can be added to the typedef
  814.    symbol table.  If the type name is subsequently encountered by the lexer,
  815.    the lexer returns a token for a type name rather than for an identifier.
  816.    This is the ugly part of C that cannot practically be expressed by a YACC
  817.    grammar specification.
  818. */
  819. static BOOLEAN is_typedef;
  820.  
  821. /*
  822.    nested_decl_specs is used to distinguish the type name of the root-level
  823.    declaration in a typedef from other identifiers in the typedef.
  824. */
  825. static unsigned nested_decl_specs;
  826.  
  827. /*
  828.    Whether the last statement was a case label.  Used to consider adjacent
  829.    case labels as one decision point.  The transition from is_case_label==TRUE
  830.    to is_case_label==FALSE is a decision point, instead of each case label
  831.    being a decision point.  Adjacent case labels are considered one decision
  832.    point because this is analogous to an if statement with or logical
  833.    operators, ||.  For example,
  834.  
  835.       switch (expr) {
  836.       case 5:
  837.       case 10:
  838.          a;
  839.       }
  840.  
  841.    is, in this regard, analogous to
  842.  
  843.       if (expr == 5 || expr == 10)
  844.          a;
  845.  
  846.    I did not want to bias the metric against the switch statement.
  847. */
  848. static BOOLEAN is_case_label;
  849.  
  850. static IDENTIFIER function_name;
  851. static IDENTIFIER last_identifier;
  852.  
  853. /* Static function declarations. */
  854.  
  855. static void fire_fcn(void);
  856. static void fire_stm(void);
  857. static void print_exception(int, char *, char *, va_list);
  858. static void typedef_symbol_table_add(char *);
  859. static void case_label(void);
  860. static void not_case_label(void);
  861. static void check_starting_options(void);
  862. static void print_banner(void);
  863. static void print_help(void);
  864. static void stat_func_begin(void);
  865. static void stat_func_end(void);
  866. static void check_multiple_statements(void);
  867. static void int_fatal(int, char *, ...);
  868. static void int_warn(int, char *, ...);
  869.  
  870.  
  871. /* Functions. */
  872.  
  873. main(int argc, char *argv[])
  874. {
  875.    print_banner();
  876.  
  877.    /* Save so that the argument list may be accessed globally. */
  878.    cmd_line_argv = argv;
  879.    cmd_line_argc = argc;
  880.  
  881.    /* Get command-line options that affect Metre at the start. */
  882.    check_starting_options();
  883.  
  884.    /* Initialize YACC and Lex. */
  885.    init_yacc();
  886.    init_lex();
  887.  
  888.    /*
  889.       Look for the first input file and first original name of that input file.
  890.    */
  891.    next_cmd_line_file = 0;
  892.    next_cmd_line_file_orig_n = 0;
  893.    if ((input_file = get_next_input_file(&next_cmd_line_file)) != NULL)
  894.       if ((yyin = fopen(input_file, "r")) != NULL)
  895.       {
  896.          input_file_orig_name =
  897.                get_next_input_file_orig_name(&next_cmd_line_file_orig_n);
  898.          /* If no original name given, use the actual as the original, also. */
  899.          if (input_file_orig_name == NULL)
  900.             input_file_orig_name = input_file;
  901.  
  902.          /* Fire the beginning-of-project trigger. */
  903.          ZERO(int_prj);
  904.          int_prj.begin = TRUE;
  905.          fire_prj();
  906.          int_prj.begin = FALSE;
  907.  
  908.          /* Fire the beginning-of-module trigger. */
  909.          ZERO(int_mod);
  910.          int_mod.begin = TRUE;
  911.          fire_mod();
  912.          int_mod.begin = FALSE;
  913.  
  914.          /*
  915.             Call the YACC-generated parser to wade through the input file(s).
  916.             When all done, close the last input file.  yywrap() could have
  917.             opened any number of subsequent input files.
  918.          */
  919.          yyparse();
  920.          fclose(yyin);
  921.       }
  922.       else
  923.          int_warn(W_CANNOT_OPEN_FILE, input_file);
  924.    else
  925.       /* Since no input file specified on command line, print Metre's help. */
  926.       print_help();
  927.  
  928. /* VMS has different ideas about what constitutes a successful return value. */
  929. #ifdef VAX
  930.    return 1;
  931. #else
  932.    return 0;
  933. #endif
  934. }
  935.  
  936. /* Common exception-handling function. */
  937. static void print_exception(int n, char *severity_str, char *format, va_list ap)
  938. {
  939.    fflush(out_fp);
  940.  
  941.    /*
  942.       Display input line if supposed to, then display line with marker
  943.       character in it if appropriate.
  944.    */
  945.    if (mod_name() != NULL && strlen(mod_name()) > 0)
  946.    {
  947.       if (!int_mod.end && !int_fcn.end)
  948.       {
  949.          if (!display_input && READ_LINE)
  950.             fputs(line(), out_fp);
  951.  
  952.          if (!int_lin.end && READ_LINE)
  953.             fputs(marker(), out_fp);
  954.       }
  955.    }
  956.  
  957.    /*
  958.       Display module name and line number if a module name has been established.
  959.       If one hasn't, the error must not relate to a location in the input file.
  960.    */
  961.    if (mod_name() != NULL && strlen(mod_name()) > 0)
  962.       fprintf(out_fp, "%s(%u): ", mod_name(), yylineno);
  963.    fprintf(out_fp, "%s%04u: ", severity_str, n);
  964.  
  965.    vfprintf(out_fp, format, ap);
  966.    fputc('\n', out_fp);
  967. }
  968.  
  969. /* Print message for internal fatal error. */
  970. static void int_fatal(int n, char *format, ...)
  971. {
  972.    va_list ap;
  973.  
  974.    va_start(ap, format);
  975.  
  976.    print_exception(n, "Fatal Error ME", format, ap);
  977.  
  978.    exit(1);
  979. }
  980.  
  981. /* Print message for fatal error that occured in the rules() function. */
  982. void fatal(int n, char *format, ...)
  983. {
  984.    va_list ap;
  985.  
  986.    va_start(ap, format);
  987.  
  988.    print_exception(n, "Fatal Error E", format, ap);
  989.  
  990.    exit(1);
  991. }
  992.  
  993. /* Print message for internal warning. */
  994. static void int_warn(int n, char *format, ...)
  995. {
  996.    va_list ap;
  997.  
  998.    va_start(ap, format);
  999.  
  1000.    print_exception(n, "Warning MW", format, ap);
  1001. }
  1002.  
  1003. /* Print message for warning that occured in the rules() function. */
  1004. void warn(int n, char *format, ...)
  1005. {
  1006.    va_list ap;
  1007.  
  1008.    va_start(ap, format);
  1009.  
  1010.    print_exception(n, "Warning W", format, ap);
  1011. }
  1012.  
  1013. /* Function called by YACC when it detects an error. */
  1014. void yyerror(char *s)
  1015. {
  1016. #ifdef DEBUG_TYPEDEF
  1017.    /* Used for debugging typedef processing. */
  1018.    typedef_symbol_table_dump();
  1019. #endif
  1020.    int_fatal(0, "%s", s);
  1021. }
  1022.  
  1023. /* Add type name to the typedef symbol table. */
  1024. static void typedef_symbol_table_add(char *p_symbol)
  1025. {
  1026.    TYPEDEF_SYM_BLK *block;
  1027.    char *str_buf = (char *)malloc(strlen(p_symbol) + 1);
  1028.  
  1029.    if (str_buf == NULL)
  1030.       int_fatal(E_NO_HEAP);
  1031.  
  1032.    /* Make copy of argument. */
  1033.    strcpy(str_buf, p_symbol);
  1034.  
  1035.    /* Is symbol table empty? */
  1036.    if (typedef_sym_tbl_head == NULL)
  1037.    {
  1038.       /* Allocate first block and make the head of the table list. */
  1039.       typedef_sym_tbl_head = block = (TYPEDEF_SYM_BLK *)malloc(sizeof *block);
  1040.       if (block == NULL)
  1041.          int_fatal(E_NO_HEAP);
  1042.  
  1043.       block->total = 0;
  1044.       block->next = NULL;
  1045.    }
  1046.    else
  1047.    {
  1048.       TYPEDEF_SYM_BLK *prev_block;
  1049.  
  1050.       /* Find first block in symbol-table list that isn't full. */
  1051.       for (prev_block = NULL, block = typedef_sym_tbl_head;
  1052.             block != NULL && block->total == DIM_OF(block->id);
  1053.             prev_block = block, block = block->next)
  1054.          ;
  1055.  
  1056.       /* If all blocks are full, allocate a new one and append to list. */
  1057.       if (block == NULL)
  1058.       {
  1059.          block = (TYPEDEF_SYM_BLK *)malloc(sizeof *block);
  1060.          if (block == NULL)
  1061.             int_fatal(E_NO_HEAP);
  1062.  
  1063.          block->total = 0;
  1064.          block->next = NULL;
  1065.          if (prev_block == NULL)
  1066.             typedef_sym_tbl_head = block;
  1067.          else
  1068.             prev_block->next = block;
  1069.       }
  1070.    }
  1071.  
  1072.    /* Save pointer to the new type name in first empty slot of this block. */
  1073.    block->id[block->total++] = str_buf;
  1074. }
  1075.  
  1076. /* Return TRUE if symbol exists in the typedef symbol table. */
  1077. BOOLEAN typedef_symbol_table_find(char *p_symbol)
  1078. {
  1079.    TYPEDEF_SYM_BLK *block;
  1080.    BOOLEAN found = FALSE;
  1081.  
  1082.    /* Loop for each block of symbols. */
  1083.    for (block = typedef_sym_tbl_head; block != NULL; block = block->next)
  1084.    {
  1085.       unsigned i;
  1086.  
  1087.       /* Loop for each symbol in this block. */
  1088.       for (i = 0; i < block->total; ++i)
  1089.          if (strcmp(block->id[i], p_symbol) == 0)
  1090.             found = TRUE;
  1091.    }
  1092.  
  1093.    return found;
  1094. }
  1095.  
  1096. /*
  1097.    Remove all symbols (and symbol blocks) from the symbol table--make the
  1098.    table empty.
  1099. */
  1100. void typedef_symbol_table_flush(void)
  1101. {
  1102.    TYPEDEF_SYM_BLK *block;
  1103.  
  1104.    /* Loop for each block of symbols. */
  1105.    for (block = typedef_sym_tbl_head; block != NULL; )
  1106.    {
  1107.       unsigned i;
  1108.       TYPEDEF_SYM_BLK *temp_block;
  1109.  
  1110.       /* Loop for each symbol in this block. */
  1111.       for (i = 0; i < block->total; ++i)
  1112.          free(block->id[i]);              /* Free symbol. */
  1113.  
  1114.       temp_block = block->next;
  1115.       free(block);                        /* Free block now that it's empty. */
  1116.       block = temp_block;
  1117.    }
  1118.  
  1119.    typedef_sym_tbl_head = NULL;
  1120. }
  1121.  
  1122. #ifdef DEBUG_TYPEDEF
  1123. /*
  1124.    Display the contents of the typedef symbol table.  Used for debugging
  1125.    typedef processing.
  1126. */
  1127. void typedef_symbol_table_dump(void)
  1128. {
  1129.    TYPEDEF_SYM_BLK *block;
  1130.  
  1131.    puts("typedef symbol table dump:");
  1132.  
  1133.    /* Loop for each block of symbols. */
  1134.    for (block = typedef_sym_tbl_head; block != NULL; block = block->next)
  1135.    {
  1136.       unsigned i;
  1137.  
  1138.       /* Loop for each symbol in this block. */
  1139.       for (i = 0; i < block->total; ++i)
  1140.          puts(block->id[i]);
  1141.    }
  1142. }
  1143. #endif
  1144.  
  1145. /* Record that the last statement was a case label. */
  1146. static void case_label(void)
  1147. {
  1148.    is_case_label = TRUE;
  1149. }
  1150.  
  1151. /*
  1152.    Record that the last statement was not a case label.  If the previous
  1153.    statement was a case label, increment the decision-point counter--this ends
  1154.    a run of adjacent case labels which count as one decision point.
  1155. */
  1156. static void not_case_label(void)
  1157. {
  1158.    if (is_case_label)
  1159.    {
  1160.       is_case_label = FALSE;
  1161.       ++fcn_decisions;        /* This is a decision point. */
  1162.    }
  1163. }
  1164.  
  1165. /* Initialize parser. */
  1166. void init_yacc(void)
  1167. {
  1168.    /* Make the typedef symbol table empty. */
  1169.    typedef_symbol_table_flush();
  1170.  
  1171.    /*
  1172.       See the definition of each of these variables, above, for more
  1173.       information.
  1174.    */
  1175.    is_typedef = FALSE;
  1176.    nested_decl_specs = 0;
  1177.    is_case_label = FALSE;
  1178.  
  1179.    function_name[0] = '\0';
  1180.    last_identifier[0] = '\0';
  1181.  
  1182.    mod_decisions = 0;
  1183.    mod_functions = 0;
  1184.    is_else = is_if = FALSE;
  1185.    looking_for_tag = FALSE;
  1186.  
  1187.    is_within_function = FALSE;
  1188. }
  1189.  
  1190. /*
  1191.    Returns TRUE if the indicated option character was specified on the
  1192.    command line.  E.g., for -S, would return TRUE for option('S').
  1193. */
  1194. int option(char opt_char)
  1195. {
  1196.    char *opt_str = str_option(opt_char);
  1197.  
  1198.    return opt_str == NULL ? 0 : strlen(opt_str) == 0 ? 1 : atoi(opt_str);
  1199. }
  1200.  
  1201. /*
  1202.    Returns pointer to the part of an option following the "=".  E.g.,
  1203.    for -Xabc=def, it would point to the "def" part.
  1204. */
  1205. char *str_option(char opt_char)
  1206. {
  1207.    unsigned i;
  1208.  
  1209.    for (i = 1; i < cmd_line_argc; ++i)
  1210.       if (strchr(OPT_INTRO_CHARS, cmd_line_argv[i][0]) != NULL)
  1211.          if (toupper(cmd_line_argv[i][1]) == toupper(opt_char))
  1212.             break;
  1213.  
  1214.    return i < cmd_line_argc ? &cmd_line_argv[i][2] : NULL;
  1215. }
  1216.  
  1217. /*
  1218.    Return pointer to the name of the next input file in the argv array
  1219.    starting with the argument that p_i points to.  An input file name is
  1220.    distinguished from the command-line options by not starting with one of
  1221.    characters in the OPT_INTRO_CHARS string.
  1222.  
  1223.    NOTE: argument 0 is the name of the command, not the first argument, per se.
  1224. */
  1225. char *get_next_input_file(unsigned *p_i)
  1226. {
  1227.    for (++*p_i; *p_i < cmd_line_argc &&
  1228.          strchr(OPT_INTRO_CHARS, cmd_line_argv[*p_i][0]) != NULL; ++*p_i)
  1229.       ;
  1230.  
  1231.    return *p_i < cmd_line_argc ? cmd_line_argv[*p_i] : NULL;
  1232. }
  1233.  
  1234. /*
  1235.    Return pointer to the original name of the next input file in the argv
  1236.    array starting with the argument that p_i points to.  An original name is
  1237.    specified as a command-line option.  That is how an original name is
  1238.    distinguished from the name of an actual input file
  1239.  
  1240.    NOTE: argument 0 is the name of the command, not the first argument, per se.
  1241. */
  1242. char *get_next_input_file_orig_name(unsigned *p_i)
  1243. {
  1244.    for (++*p_i; *p_i < cmd_line_argc; ++*p_i)
  1245.       if (strchr(OPT_INTRO_CHARS, cmd_line_argv[*p_i][0]) != NULL &&
  1246.             toupper(cmd_line_argv[*p_i][1]) == SUBST_FILE_OPT_CHAR)
  1247.          break;
  1248.  
  1249.    return *p_i < cmd_line_argc ? &cmd_line_argv[*p_i][2] : NULL;
  1250. }
  1251.  
  1252. /* Returns pointer to current module (file) name. */
  1253. char *mod_name(void)
  1254. {
  1255.    return input_file_orig_name;
  1256. }
  1257.  
  1258. /* Process the command-line options that affect the start of Metre. */
  1259. static void check_starting_options(void)
  1260. {
  1261.    static char *output_file_name;
  1262.  
  1263.    /* Interleave the input with the output? */
  1264.    display_input = option(COPY_INPUT_OPT_CHAR);
  1265.  
  1266.    /*
  1267.       Name of listing file to contain output.  This for those OS's that don't
  1268.       support command-line redirection, e.g., VMS.
  1269.    */
  1270.    output_file_name = str_option(LISTING_OPT_CHAR);
  1271.    if (output_file_name != NULL && strlen(output_file_name) > 0)
  1272.    {
  1273.       out_fp = fopen(output_file_name, "w");
  1274.       if (out_fp == NULL)
  1275.       {
  1276.          out_fp = stdout;     /* Restore to previous, good output file. */
  1277.          int_fatal(E_CANT_OPEN_LISTING_FILE);   /* Die. */
  1278.       }
  1279.    }
  1280.    else
  1281.       out_fp = stdout;
  1282. }
  1283.  
  1284. /* Print name, version, and copyright notice. */
  1285. static void print_banner(void)
  1286. {
  1287.    printf("METRE Version %s  ", metre_version);
  1288.    puts("Copyright (c) 1993,1994 by Paul Long  All rights reserved.");
  1289. }
  1290.  
  1291. /* Print Metre command-usage information. */
  1292. static void print_help(void)
  1293. {
  1294.    puts("Syntax: METRE [ options ] file[s]   Option character in either case.  / or -");
  1295.    puts("-Dxxx=[xxx] Define identifier     -Lxxx  Name of listing file (stdout)");
  1296.    puts("-Sxxx       Substitute file name  -C     Copy input to output");
  1297. }
  1298.  
  1299. /* Called at the beginning of a function definition. */
  1300. static void stat_func_begin(void)
  1301. {
  1302.    /* Fire the beginning-of-function trigger. */
  1303.    ZERO(int_fcn);
  1304.    int_fcn.begin = TRUE;
  1305.    fire_fcn();
  1306.    int_fcn.begin = FALSE;
  1307.  
  1308.    /* Initialize variables relating to a function. */
  1309.    depth = 0;
  1310.    is_within_function = TRUE;
  1311.    fcn_decisions = 0;
  1312.    previous_statements_line_number = 0;
  1313.  
  1314.    /* Install starting counts.  Will replace with deltas at end-of-function. */
  1315.    int_fcn.lines.white = int_mod.lines.white;
  1316.    int_fcn.lines.com = int_mod.lines.com;
  1317.    int_fcn.lines.exec = int_mod.lines.exec;
  1318.    int_fcn.lines.total = yylineno;
  1319. }
  1320.  
  1321. /* Called at the end of a function definition. */
  1322. static void stat_func_end(void)
  1323. {
  1324.    /*
  1325.       Replace initial counts with their deltas to arrive at totals for
  1326.       the function.
  1327.    */
  1328.    int_fcn.lines.white = int_mod.lines.white - int_fcn.lines.white;
  1329.    int_fcn.lines.com = int_mod.lines.com - int_fcn.lines.com;
  1330.    int_fcn.lines.exec = int_mod.lines.exec - int_fcn.lines.exec;
  1331.    int_fcn.lines.total = yylineno - int_fcn.lines.total;
  1332.  
  1333.    ++mod_functions;                 /* Increment function count. */
  1334.  
  1335.    /* Accumulate function decision count into module decision count. */
  1336.    mod_decisions += fcn_decisions;
  1337.  
  1338.    /*
  1339.       Install the rest of the function-related information into the function
  1340.       structure and fire the end-of-function trigger.
  1341.    */
  1342.    int_fcn.decisions = fcn_decisions;
  1343.    int_fcn.end = TRUE;
  1344.    fire_fcn();
  1345.    ZERO(int_fcn);
  1346.  
  1347.    /*
  1348.       Clear variables that would otherwise indicate that we are still
  1349.       parsing a function.
  1350.    */
  1351.    strcpy(function_name, "");
  1352.    is_within_function = FALSE;
  1353. }
  1354.  
  1355. /*
  1356.    Returns pointer to current function name, or an empty string if not in a
  1357.    function.
  1358. */
  1359. char *fcn_name(void)
  1360. {
  1361.    return function_name;
  1362. }
  1363.  
  1364. /*
  1365.    Increment the number of statements for the current line.  This function is
  1366.    called whenever a statement is encountered.  If the current line number is
  1367.    the same as when the last statement was encountered and if this is not the
  1368.    special situation of "else if," the counter is incremented.
  1369. */
  1370. static void check_multiple_statements(void)
  1371. {
  1372.    if (previous_statements_line_number == yylineno)
  1373.       if (is_else && is_if)
  1374.          ;        /* do nothing */
  1375.       else
  1376.          ++int_lin.statements;
  1377.    else
  1378.       previous_statements_line_number = yylineno;
  1379.  
  1380.    is_else = is_if = FALSE;
  1381. }
  1382.  
  1383.  
  1384. /*
  1385.    This is true for all of the fire_*() functions: Copy the internal structure
  1386.    to the exported structure, allow the triggers to fire in the rules()
  1387.    function, then zero-fill the exported structure so that unrelated rules
  1388.    won't execute when other triggers are fired.
  1389. */
  1390.  
  1391. void fire_prj(void)
  1392. {
  1393.    prj = int_prj;
  1394.    rules();
  1395.    ZERO(prj);
  1396. }
  1397.  
  1398. void fire_mod(void)
  1399. {
  1400.    mod = int_mod;
  1401.    rules();
  1402.    ZERO(mod);
  1403. }
  1404.  
  1405. static void fire_fcn(void)
  1406. {
  1407.    fcn = int_fcn;
  1408.    rules();
  1409.    ZERO(fcn);
  1410. }
  1411.  
  1412. static void fire_stm(void)
  1413. {
  1414.    stm = int_stm;
  1415.    rules();
  1416.    ZERO(stm);
  1417. }
  1418.  
  1419. void fire_lin(void)
  1420. {
  1421.    lin = int_lin;
  1422.    rules();
  1423.    ZERO(lin);
  1424. }
  1425.  
  1426. void fire_lex(void)
  1427. {
  1428.    lex = int_lex;
  1429.    rules();
  1430.    ZERO(lex);
  1431. }
  1432.